﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JmShared;
using System.IO;


using System.Globalization;
using Newtonsoft.Json;
using System.Diagnostics;
//using System.Xml.Serialization;
using System.Runtime.Serialization.Json;
using System.Security;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;
using System.Collections;
using System.Security.Cryptography;

namespace WebSocketServer.Utilities
{
    public static class StaticMethods
    {
        // Create an md5 sum string of this string

        static public string GetMd5Sum(string str)
        {
            // First we need to convert the string into bytes, which
            // means using a text encoder.
            Encoder enc = System.Text.Encoding.Unicode.GetEncoder();
            // Create a buffer large enough to hold the string
            byte[] unicodeText = new byte[str.Length * 2];
            enc.GetBytes(str.ToCharArray(), 0, str.Length, unicodeText, 0, true);
            // Now that we have a byte array we can ask the CSP to hash it
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash(unicodeText);
            // Build the final string by converting each byte
            // into hex and appending it to a StringBuilder
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < result.Length; i++)
            {
                sb.Append(result[i].ToString("X2"));
            }
            // And return it
            return sb.ToString();
        }

    /// <summary>
    /// Clone the object, and returning a reference to a cloned object.
    /// </summary>
    /// <returns>Reference to the new cloned 
    /// object.</returns>
    public static T Clone<T>(T source)
    {
        //First we create an instance of this specific type.
        object newObject  = Activator.CreateInstance( source.GetType() );

        //We get the array of fields for the new type instance.
        FieldInfo[] fields = newObject.GetType().GetFields();

        int i = 0;

        foreach (FieldInfo fi in source.GetType().GetFields())
        {
            //We query if the fiels support the ICloneable interface.
            Type ICloneType = fi.FieldType.
                        GetInterface( "ICloneable" , true );

            if( ICloneType != null )
            {
                //Getting the ICloneable interface from the object.
                ICloneable IClone = (ICloneable)fi.GetValue(source);

                //We use the clone method to set the new value to the field.
                fields[i].SetValue( newObject , IClone.Clone() );
            }
            else
            {
                // If the field doesn't support the ICloneable 
                // interface then just set it.
                fields[i].SetValue(newObject, fi.GetValue(source));
            }

            //Now we check if the object support the 
            //IEnumerable interface, so if it does
            //we need to enumerate all its items and check if 
            //they support the ICloneable interface.
            Type IEnumerableType = fi.FieldType.GetInterface
                            ( "IEnumerable" , true );
            if( IEnumerableType != null )
            {
                //Get the IEnumerable interface from the field.
                IEnumerable IEnum = (IEnumerable)fi.GetValue(source);

                //This version support the IList and the 
                //IDictionary interfaces to iterate on collections.
                Type IListType = fields[i].FieldType.GetInterface
                                    ( "IList" , true );
                Type IDicType = fields[i].FieldType.GetInterface
                                    ( "IDictionary" , true );

                int j = 0;
                if( IListType != null )
                {
                    //Getting the IList interface.
                    IList list = (IList)fields[i].GetValue(newObject);

                    foreach( object obj in IEnum )
                    {
                        //Checking to see if the current item 
                        //support the ICloneable interface.
                        ICloneType = obj.GetType().
                            GetInterface( "ICloneable" , true );
                        
                        if( ICloneType != null )
                        {
                            //If it does support the ICloneable interface, 
                            //we use it to set the clone of
                            //the object in the list.
                            ICloneable clone = (ICloneable)obj;

                            list[j] = clone.Clone();
                        }

                        //NOTE: If the item in the list is not 
                        //support the ICloneable interface then in the 
                        //cloned list this item will be the same 
                        //item as in the original list
                        //(as long as this type is a reference type).

                        j++;
                    }
                }
                else if( IDicType != null )
                {
                    //Getting the dictionary interface.
                    IDictionary dic = (IDictionary)fields[i].
                                        GetValue(newObject);
                    j = 0;
                    
                    foreach( DictionaryEntry de in IEnum )
                    {
                        //Checking to see if the item 
                        //support the ICloneable interface.
                        ICloneType = de.Value.GetType().
                            GetInterface( "ICloneable" , true );

                        if( ICloneType != null )
                        {
                            ICloneable clone = (ICloneable)de.Value;

                            dic[de.Key] = clone.Clone();
                        }
                        j++;
                    }
                }
            }
            i++;
        }
        return (T)newObject;
    }

        

        public static string FileNameFriendly(string filename)
        {
            //n = n.Replace("*", "~");
            //n = n.Replace("|", "-");
            //n = n.Replace(@"\", "'");
            //n = n.Replace("/", "_");
            //n = n.Replace(":", ".");
            //n = n.Replace("<", "(");
            //n = n.Replace(">", ")");
            //n = n.Replace("?", "^");
            //n = n.Replace('"'.ToString(CultureInfo.InvariantCulture), "");
            //n = n.Trim();
            //return n;
             IList<char> invalidFileNameChars = Path.GetInvalidFileNameChars();

            // Builds a string out of valid chars and replaces invalid chars with a unique letter
             var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? Convert.ToChar(invalidFileNameChars.IndexOf(ch) + 65) : ch).ToArray());
             return validFilename;
        }
        private static byte[] GetBytes(string str)
        {
            byte[] bytes = new byte[str.Length * sizeof(char)];
            System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
            return bytes;
        }
        public static string ObjectToString<T>(T input)
        {
            //using (MemoryStream msTestString = new MemoryStream())
            //{

            //    ProtoBuf.Serializer.Serialize(msTestString, input);

            //    string stringBase64 = Convert.ToBase64String(msTestString.ToArray());
            //    return stringBase64;
            //}
  //          return Convert.ToBase64String(GetBytes(JsonConvert.SerializeObject(input, Formatting.Indented,
  //new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore })));



            //using (MemoryStream stream = new MemoryStream())
            //{
            //    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));

            //    ser.WriteObject(stream, input);
            //    string str = Encoding.UTF8.GetString(stream.ToArray());
            //    stream.Dispose();
            //    return str;
            //}
            var settings = new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All,
                ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
                NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
                ObjectCreationHandling = ObjectCreationHandling.Auto,
                Formatting = Formatting.None
            };
            return JsonConvert.SerializeObject(input,settings);
        }

        public static T StringToObject<T>(string input)
        {
            if (String.IsNullOrEmpty(input))
                return default(T);
            var settings = new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All,
                ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
                NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
                ObjectCreationHandling = ObjectCreationHandling.Auto,
                Formatting = Formatting.None
            };
              return JsonConvert.DeserializeObject<T>(input,settings);
            //using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(input)))
            //{
            //    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
            //    T obj = (T)ser.ReadObject(stream);
            //    // stream.Dispose();
            //    return obj;
            //}

        }
        public static SecureString ToSecureString(string input)
        {
            SecureString secure = new SecureString();
            foreach (char c in input)
            {
                secure.AppendChar(c);
            }
            secure.MakeReadOnly();
            return secure;
        }

        public static string ToInsecureString(SecureString input)
        {
            string returnValue = string.Empty;
            IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
            try
            {
                returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
            }
            finally
            {
                System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
            }
            return returnValue;
        }
  //      public static string ObjectToString<T>(T input)
  //      {

  //          //using (MemoryStream msTestString = new MemoryStream())
  //          //{
               
  //          //    Serializer.Serialize(msTestString, input);

  //          //    string stringBase64 = Convert.ToBase64String(msTestString.ToArray());
  //          //    return stringBase64;
  //          //}
  //          return JsonConvert.SerializeObject(input, Formatting.Indented,
  //new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
  //      }
  //      public static T StringToObject<T>(string input)
  //      {
  //          if (String.IsNullOrEmpty(input))
  //              return default(T);

  //          return JsonConvert.DeserializeObject<T>(input);
  //          //byte[] byteAfter64 = Convert.FromBase64String(input);
  //          //MemoryStream afterStream = new MemoryStream(byteAfter64);


  //          //return (T)Serializer.Deserialize<T>(afterStream);
  
  //      }
    }
}
